bitkeeper revision 1.260 (3f042d1dYDmgfLY_ZLTlHlDZ45a_hA)
authorrac61@labyrinth.cl.cam.ac.uk <rac61@labyrinth.cl.cam.ac.uk>
Thu, 3 Jul 2003 13:18:21 +0000 (13:18 +0000)
committerrac61@labyrinth.cl.cam.ac.uk <rac61@labyrinth.cl.cam.ac.uk>
Thu, 3 Jul 2003 13:18:21 +0000 (13:18 +0000)
Refactor domctl into new tool, xenctl-cmdline, ready for combining with vd manager (and future porting of xenctl web interface to new backend)

26 files changed:
.rootkeys
BitKeeper/etc/logging_ok
tools/control/Makefile
tools/control/build-cmdline.xml [new file with mode: 0644]
tools/control/src/org/xenoserver/cmdline/CommandParser.java [new file with mode: 0644]
tools/control/src/org/xenoserver/cmdline/Main.java [new file with mode: 0644]
tools/control/src/org/xenoserver/cmdline/ParseDestroy.java [new file with mode: 0644]
tools/control/src/org/xenoserver/cmdline/ParseFailedException.java [new file with mode: 0644]
tools/control/src/org/xenoserver/cmdline/ParseHelp.java [new file with mode: 0644]
tools/control/src/org/xenoserver/cmdline/ParseList.java [new file with mode: 0644]
tools/control/src/org/xenoserver/cmdline/ParseNew.java [new file with mode: 0644]
tools/control/src/org/xenoserver/cmdline/ParseStart.java [new file with mode: 0644]
tools/control/src/org/xenoserver/cmdline/ParseStop.java [new file with mode: 0644]
tools/control/src/org/xenoserver/control/Command.java [new file with mode: 0644]
tools/control/src/org/xenoserver/control/CommandDestroy.java [new file with mode: 0644]
tools/control/src/org/xenoserver/control/CommandFailedException.java [new file with mode: 0644]
tools/control/src/org/xenoserver/control/CommandList.java [new file with mode: 0644]
tools/control/src/org/xenoserver/control/CommandNew.java [new file with mode: 0644]
tools/control/src/org/xenoserver/control/CommandStart.java [new file with mode: 0644]
tools/control/src/org/xenoserver/control/CommandStop.java [new file with mode: 0644]
tools/control/src/org/xenoserver/control/Defaults.java [new file with mode: 0644]
tools/control/src/org/xenoserver/control/Domain.java [new file with mode: 0644]
tools/control/src/org/xenoserver/control/InetAddressPattern.java [new file with mode: 0644]
tools/control/src/org/xenoserver/control/Settings.java [new file with mode: 0644]
tools/control/src/org/xenoserver/control/StringPattern.java [new file with mode: 0644]
tools/control/xenctl [new file with mode: 0755]

index 5e185dc23760f7399609c0c9b40a14a32a55e0e5..da43d13fe273a8b8db54010f6111220461009ac7 100644 (file)
--- a/.rootkeys
+++ b/.rootkeys
@@ -8,12 +8,34 @@
 3e6377dbGcgnisKw16DPCaND7oGO3Q tools/balloon/balloon.c
 3eb781edFwm_pW9FwnQACIe68viLOw tools/control/Makefile
 3eca6a96a31IwaKtkEa4jmzwTWlm8Q tools/control/README-xenctl
+3eb781fceEYkUi1XHKf2V0KX7si2JA tools/control/build-cmdline.xml
 3eb781fcTp_LPQwaot3SSSehkaf4eg tools/control/build-dom.xml
 3ec41f7cWCxQ8pdH8ZWqhhv-38qQ1w tools/control/build-xen.xml
 3ec41f7ca6IBXDSe0HVcMPp3PPloOQ tools/control/build.properties
 3ec4ebe0g_MI1VqkbbyNB8gt6m0Adg tools/control/docs/empty_dir
 3eb781fcXf-WczEdAhnTpWfbR55jqA tools/control/domctl
 3eb781fcabCKRogwxJA3-jJKstw9Vg tools/control/domctl.xml
+3f042c35FzVap5QW0UBPnZ2ZM0l3QA tools/control/src/org/xenoserver/cmdline/CommandParser.java
+3eb781fdNQvEJW3tNvovjqoN7GlePA tools/control/src/org/xenoserver/cmdline/Main.java
+3f042c35-TPgpCQViIaJzLts2-CnBw tools/control/src/org/xenoserver/cmdline/ParseDestroy.java
+3f042c35UhRkvblwKSx0KW2QHUn3Fw tools/control/src/org/xenoserver/cmdline/ParseFailedException.java
+3f042c35Inw0LzkOzXo9ncbEHZzUHA tools/control/src/org/xenoserver/cmdline/ParseHelp.java
+3f042c35h9GAWRu7wimPjBpCi09nUA tools/control/src/org/xenoserver/cmdline/ParseList.java
+3f042c359mRNaxBYXFwVsmv5-J_DJA tools/control/src/org/xenoserver/cmdline/ParseNew.java
+3f042c35bMvqLB4Yc-0Dxs4WlYHHpw tools/control/src/org/xenoserver/cmdline/ParseStart.java
+3f042c35Lc-JegNavF6Bj6coM486Ig tools/control/src/org/xenoserver/cmdline/ParseStop.java
+3f042c35V-Bf3dlIe1r5mZs8ZTPSvA tools/control/src/org/xenoserver/control/Command.java
+3f042c35U_4O2eovLKUgo2avPPHKUw tools/control/src/org/xenoserver/control/CommandDestroy.java
+3f042c35hdwL__Airzyz4HutOgGRqQ tools/control/src/org/xenoserver/control/CommandFailedException.java
+3f042c3570VRwuzl94tEozOIVBycNg tools/control/src/org/xenoserver/control/CommandList.java
+3f042c35xVm-ucJAVdvC3acD6ZEe2Q tools/control/src/org/xenoserver/control/CommandNew.java
+3f042c36GqoXJJj_BvWGwBeKwEzgvg tools/control/src/org/xenoserver/control/CommandStart.java
+3f042c36bmZJD0xrxURD075avUlIUg tools/control/src/org/xenoserver/control/CommandStop.java
+3eb781fdBRXfSlWzK6GXlIQIlHFoaQ tools/control/src/org/xenoserver/control/Defaults.java
+3ec41f7cQ7Ug739JBDrsVH-7KJ5MvQ tools/control/src/org/xenoserver/control/Domain.java
+3eb781fdDeZEopemXIVg_ARCGKSmBw tools/control/src/org/xenoserver/control/InetAddressPattern.java
+3eb781fdmMkFbyb2SAGR0vsuFtl9Lw tools/control/src/org/xenoserver/control/Settings.java
+3eb781fdpgi83RpUvQWVccWjsDJK7w tools/control/src/org/xenoserver/control/StringPattern.java
 3eb781fcffCXkrcWLBxUTOfQFa3Saw tools/control/src/uk/ac/cam/cl/xeno/domctl/Command.java
 3eb781fcOLcVAcqnZOAikur6sAP0rA tools/control/src/uk/ac/cam/cl/xeno/domctl/CommandDestroy.java
 3eb781fcQuQVSKxKtp4fBgPOwx7DDw tools/control/src/uk/ac/cam/cl/xeno/domctl/CommandHelp.java
 3ec41f7ecn3uvsSrOVxKC8G8ACuulg tools/control/web/tmpl/xenofoot.def
 3ec41f7ek1RffqN2yRUzSTkD5m1J6w tools/control/web/tmpl/xenohead.def
 3ec41f7e1ZpfCsgQ2qRJBooBn_iRtA tools/control/web/tmpl/xenostyle.css
+3eb781fc6vgq5yhkJRGDLY9gWWRY2A tools/control/xenctl
 3e4d00468-FN2VDeEHo96zxrMHK_mA tools/domain_builder/Makefile
 3e4d0046SPau_y0sw2WLJz8QkqNoRA tools/domain_builder/README
 3e4d0046bbdH0GsI9J_1Eb4ZQHfIiQ tools/domain_builder/dom0_defs.h
index b32e0409d04eb996c1137f675169c7038f79f8c9..ccc56529db6c30c08f34f4297b9fcf3b4a6bf352 100644 (file)
@@ -15,6 +15,7 @@ kaf24@plym.cl.cam.ac.uk
 kaf24@scramble.cl.cam.ac.uk
 kaf24@striker.cl.cam.ac.uk
 lynx@idefix.cl.cam.ac.uk
+rac61@labyrinth.cl.cam.ac.uk
 rgr22@boulderdash.cl.cam.ac.uk
 rn@wyvis.camb.intel-research.net
 rn@wyvis.research.intel-research.net
index f78d796d652dffa05732a63a01e0135d91f0673c..fcf244a44573dac5c83751e5a234e14d3ee09e77 100644 (file)
@@ -1,8 +1,21 @@
-default: domctl xenctl
+default: cmdline
 
-install: install-domctl install-xenctl
+install: install-cmdline
 
-clean: clean-domctl clean-xenctl
+clean: clean-cmdline
+
+
+
+cmdline: FORCE
+       ant -buildfile build-cmdline.xml dist
+
+install-cmdline: domctl
+       cp xenctl-cmdline.jar xenctl ../../../install/bin
+       chmod 755 ../../../install/bin/xenctl
+
+clean-cmdline:
+       ant -buildfile build-cmdline.xml clean
+       rm -f xenctl-cmdline.jar
 
 
 
diff --git a/tools/control/build-cmdline.xml b/tools/control/build-cmdline.xml
new file mode 100644 (file)
index 0000000..4cf6fbf
--- /dev/null
@@ -0,0 +1,50 @@
+<project name="xenctl cmdline project" default="compile">
+  <property name="src" location="src"/>
+  <property name="build" location="build-cmdline"/>
+
+  <target name="init">
+    <tstamp/>
+    <mkdir dir="${build}"/>     
+  </target>
+
+  <target name="compile" depends="init">
+    <javac srcdir="${src}" destdir="${build}" debug="on">
+      <include name="org/xenoserver/cmdline/**"/>
+      <include name="org/xenoserver/control/**"/>
+    </javac>
+  </target>
+
+  <target name="dist" depends="compile">
+    <jar jarfile="xenctl-cmdline.jar"
+         excludes="*~"
+        basedir="${build}">
+      <fileset dir="${src}">
+        <include name="org/xenoserver/cmdline/**"/>
+        <include name="org/xenoserver/control/**"/>
+      </fileset>
+      <fileset dir=".">
+        <include name="build-cmdline.xml"/>
+        <include name="xenctl"/>
+        <include name="domctl.xml"/>
+        <include name="Makefile"/>
+      </fileset>
+      <manifest>
+        <attribute name="Built-By" value="${user.name}"/>
+       <attribute name="Main-Class" value="org.xenoserver.cmdline.Main"/>
+       <attribute name="Sealed" value="true"/>
+      </manifest>
+    </jar>
+  </target>
+
+  <target name="test" depends="compile">
+    <java fork="true" classname="org.xenoserver.cmdline.Main">
+      <classpath>
+        <pathelement path="${build}"/>
+      </classpath>
+    </java>
+  </target>
+
+  <target name="clean">
+    <delete dir="${build}"/>
+  </target>
+</project>
\ No newline at end of file
diff --git a/tools/control/src/org/xenoserver/cmdline/CommandParser.java b/tools/control/src/org/xenoserver/cmdline/CommandParser.java
new file mode 100644 (file)
index 0000000..3f4fc85
--- /dev/null
@@ -0,0 +1,70 @@
+package org.xenoserver.cmdline;
+
+import org.xenoserver.control.Command;
+import org.xenoserver.control.CommandFailedException;
+import org.xenoserver.control.Defaults;
+
+/**
+ * Subclasses of Parser know how to parse arguments for a given command
+ * and execute it, displaying any output.
+ */
+public abstract class CommandParser {
+  /**
+   * Subclasses should implement this method such that it outputs any successful
+   * output to the screen, or throws an exception if required arguments
+   * are missing or malformed. It also may propagate exceptions from the
+   * command execution.
+   * 
+   * @param d The defaults object to use.
+   * @param args The arguments to parse.
+   * @throws ParseFailedException if the arguments are not suitable.
+   * @throws CommandFailedException if the command did not execute successfully.
+   */
+  public abstract void parse(Defaults d, String args[]) throws ParseFailedException, CommandFailedException;
+
+  /** Return the command name which will be matched on the command line. */  
+  public abstract String getName();     
+  /** Return a usage string for this command. */
+  public abstract String getUsage();
+  /** Return the help text for this command. */
+  public abstract String getHelpText();
+
+  public String getStringParameter(String args[], char key, String def)
+  {
+    String r = getParameter (args, key);
+    return (r == null) ? def : r;
+  }
+
+  public int getIntParameter(String args[], char key, int def)
+  {
+    String r = getParameter (args, key);
+    return (r == null) ? def : (Integer.parseInt (r));
+  }
+
+  public boolean getFlagParameter(String args[], char key)
+  {
+    String r = getParameter (args, key);
+    return (r == null) ? false : true;
+  }
+
+  protected String getParameter (String args[], char key)
+  {
+    int i;
+    String result = null;
+    for (i = 0; i < args.length; i ++)
+      {
+  if (args[i].startsWith("-" + key)) 
+    {
+      if (args[i].length() > 2)
+        {
+    result = args[i].substring(2, args[i].length());
+        }
+      else
+        {
+    result = "";
+        }
+    }
+      }
+    return result;
+  }
+}
diff --git a/tools/control/src/org/xenoserver/cmdline/Main.java b/tools/control/src/org/xenoserver/cmdline/Main.java
new file mode 100644 (file)
index 0000000..a85c192
--- /dev/null
@@ -0,0 +1,49 @@
+package org.xenoserver.cmdline;
+
+import org.xenoserver.control.CommandFailedException;
+import org.xenoserver.control.Defaults;
+
+public class Main {
+  private static ParseHelp help = new ParseHelp();
+  static CommandParser commands[] =
+    { help,
+      new ParseNew(),
+      new ParseStart(),
+      new ParseStop(),
+      new ParseDestroy(),
+      new ParseList() };
+
+  public static void main(String[] args) {
+    Defaults d = new Defaults();
+    int ec = -1;
+
+    if (args.length == 0) {
+      help.parse(d, args);
+    } else {
+      String c = args[0];
+      int i;
+      for (i = 0; i < commands.length; i++) {
+        if (commands[i].getName().equals(c)) {
+          if (commands[i].getFlagParameter(args, '?')) {
+            help.doHelpFor(commands[i]);
+          } else {
+            try {
+              commands[i].parse(d, args);
+              ec = 0;
+            } catch (ParseFailedException e) {
+              System.err.println( e.getMessage() );
+            } catch (CommandFailedException e) {
+              System.err.println( e.getMessage() );
+            }
+          }
+          break;
+        }
+      }
+      if (i == commands.length) {
+        System.out.println("Unknown command " + c);
+      }
+    }
+
+    System.exit(ec);
+  }
+}
diff --git a/tools/control/src/org/xenoserver/cmdline/ParseDestroy.java b/tools/control/src/org/xenoserver/cmdline/ParseDestroy.java
new file mode 100644 (file)
index 0000000..4368c9d
--- /dev/null
@@ -0,0 +1,37 @@
+package org.xenoserver.cmdline;
+
+import org.xenoserver.control.Command;
+import org.xenoserver.control.CommandDestroy;
+import org.xenoserver.control.CommandFailedException;
+import org.xenoserver.control.Defaults;
+
+public class ParseDestroy extends CommandParser {
+  public void parse(Defaults d, String[] args) throws ParseFailedException, CommandFailedException {
+    int domain_id = getIntParameter(args, 'n', 0);
+    boolean force = getFlagParameter(args, 'f');
+
+    if (domain_id == 0) {
+      throw new ParseFailedException("Expected -n<domain_id>");
+    }
+
+    String output = new CommandDestroy(d, domain_id, force).execute();
+    if ( output != null )
+      System.out.println( output );
+  }
+  
+  public String getName()
+  {
+    return "destroy";
+  }
+
+  public String getUsage()
+  {
+    return "[-f] [-n<domain_id>]";
+  }
+
+  public String getHelpText()
+  {
+    return
+      "Destory the specified domain.  -f forcibly destroys it.";
+  }
+}
diff --git a/tools/control/src/org/xenoserver/cmdline/ParseFailedException.java b/tools/control/src/org/xenoserver/cmdline/ParseFailedException.java
new file mode 100644 (file)
index 0000000..6e51be3
--- /dev/null
@@ -0,0 +1,22 @@
+package org.xenoserver.cmdline;
+
+/**
+ * Thrown when a command line could not be parsed.
+ */
+public class ParseFailedException extends Exception {
+  public ParseFailedException() {
+    super();
+  }
+
+  public ParseFailedException(String message) {
+    super(message);
+  }
+
+  public ParseFailedException(String message, Throwable cause) {
+    super(message, cause);
+  }
+
+  public ParseFailedException(Throwable cause) {
+    super(cause);
+  }
+}
diff --git a/tools/control/src/org/xenoserver/cmdline/ParseHelp.java b/tools/control/src/org/xenoserver/cmdline/ParseHelp.java
new file mode 100644 (file)
index 0000000..0a8362e
--- /dev/null
@@ -0,0 +1,53 @@
+package org.xenoserver.cmdline;
+
+import org.xenoserver.control.Command;
+import org.xenoserver.control.Defaults;
+
+public class ParseHelp extends CommandParser {
+
+  public void parse(Defaults d, String[] args) {
+    if (args.length <= 1) {
+      System.out.println("Usage:");
+      for (int i = 0; i < Main.commands.length; i++) {
+        String name = Main.commands[i].getName();
+        String usage = Main.commands[i].getUsage();
+        while (name.length() < 12)
+          name = name + " ";
+        System.out.println("   " + name + usage);
+      }
+    } else {
+      for (int i = 0; i < Main.commands.length; i++) {
+        String name = Main.commands[i].getName();
+        String usage = Main.commands[i].getUsage();
+        if (name.equals(args[1])) {
+          doHelpFor(Main.commands[i]);
+          break;
+        }
+      }
+    }
+
+    System.out.println("");
+  }
+  
+  public void doHelpFor(CommandParser c)
+  {
+    System.out.println ("xenctl " + c.getName() + " " + c.getUsage());
+    System.out.println ();
+    System.out.println (c.getHelpText ());
+  }
+
+  public String getName()
+  {
+    return "help";
+  }
+
+  public String getUsage()
+  {
+    return "";
+  }
+
+  public String getHelpText()
+  {
+    return "This message";
+  }  
+}
diff --git a/tools/control/src/org/xenoserver/cmdline/ParseList.java b/tools/control/src/org/xenoserver/cmdline/ParseList.java
new file mode 100644 (file)
index 0000000..72d81c5
--- /dev/null
@@ -0,0 +1,46 @@
+package org.xenoserver.cmdline;
+
+import org.xenoserver.control.Command;
+import org.xenoserver.control.CommandFailedException;
+import org.xenoserver.control.CommandList;
+import org.xenoserver.control.Defaults;
+import org.xenoserver.control.Domain;
+
+public class ParseList extends CommandParser {
+
+  public void parse(Defaults d, String[] args) throws ParseFailedException, CommandFailedException {
+    CommandList list = new CommandList(d);
+    String output = list.execute();
+    if ( output != null )
+      System.out.println( output );
+    Domain[] domains = list.domains();
+
+    for (int loop = 0; loop < domains.length; loop++)
+    {
+      System.out.println ("id: " + domains[loop].id + 
+        " (" + domains[loop].name+ ")");
+      System.out.println ("  processor: " + domains[loop].processor);
+      System.out.println ("  has cpu: " + domains[loop].cpu);
+      System.out.println ("  state: " + domains[loop].nstate + " " +
+        domains[loop].state);
+      System.out.println ("  mcu advance: " + domains[loop].mcu);
+      System.out.println ("  total pages: " + domains[loop].pages);
+    }
+  }
+
+  public String getName()
+  {
+    return "list";
+  }
+
+  public String getUsage()
+  {
+    return "";
+  }
+
+  public String getHelpText()
+  {
+    return
+      "List domain information";
+  }
+}
diff --git a/tools/control/src/org/xenoserver/cmdline/ParseNew.java b/tools/control/src/org/xenoserver/cmdline/ParseNew.java
new file mode 100644 (file)
index 0000000..5ddfd7a
--- /dev/null
@@ -0,0 +1,81 @@
+package org.xenoserver.cmdline;
+
+import org.xenoserver.control.Command;
+import org.xenoserver.control.CommandFailedException;
+import org.xenoserver.control.CommandNew;
+import org.xenoserver.control.Defaults;
+
+public class ParseNew extends CommandParser {
+
+  public void parse(Defaults d, String[] args) throws ParseFailedException, CommandFailedException {
+    String name = getStringParameter(args, 'n', d.domainName);
+    int size = getIntParameter(args, 'k', d.domainSizeKB);
+    String image = getStringParameter(args, 'i', d.domainImage);
+    String initrd = getStringParameter (args, 'r', d.domainInitRD);
+    int vifs = getIntParameter(args, 'v', d.domainVIFs);
+    String bargs = getStringParameter (args, 'a', d.args) + " ";
+    String root_dev = getStringParameter (args, 'd', d.rootDevice);
+    String nfs_root_path = getStringParameter (args, 'f', d.NWNFSRoot);
+    String nw_ip = getStringParameter (args, '4', d.NWIP);
+    String nw_gw = getStringParameter (args, 'g', d.NWGW);
+    String nw_mask = getStringParameter (args, 'm', d.NWMask);
+    String nw_nfs_server = getStringParameter (args, 's', d.NWNFSServer);
+    String nw_host = getStringParameter (args, 'h', d.NWHost);
+
+    d.describe();
+
+    CommandNew c = new CommandNew(d, name, size, image, initrd, vifs,
+                                  bargs, root_dev, nfs_root_path,
+                                  nw_ip, nw_gw, nw_mask, nw_nfs_server, nw_host);
+    c.execute();
+    String[] output = c.output();
+    for ( int i = 0; i < output.length; i++ )
+      System.out.println( output[i] ); 
+  }
+
+  public String getName()
+  {
+    return "new";
+  }
+
+  public String getUsage()
+  {
+    return "[-n<domain_name>] [-k<size>] [-i<image>] [-v<num_vifs>] [-r<initrd>] [-d<root_device>] [-f<nfs_root>] [-s<nfs_boot_server>] [-4<ipv4_boot_address>] [-g<ipv4_boot_gateway>] [-m<ipv4_boot_netmask>] [-h<hostname>] [-a<args>]";
+  }
+
+  public String getHelpText()
+  {
+    return
+      "Create a new domain.  Note that most of the parameters will assume\n" +
+      "default values: it should not be necessary to specify them all. See\n" +
+      "domctl.xml for the current default settings.\n" +
+      "\n" +
+      "General command line options:\n" +
+      "  -n  Domain name                              domain_name\n" +
+      "  -k  Domain size (kb)                         domain_size_kb\n" +
+      "  -i  Domain image name                        domain_image\n" +
+      "  -v  Number of VIFs                           domain_vifs\n" +
+      "  -r  InitRD (if required)                     domain_init_rd\n" +
+      "  -d  Root device (e.g /dev/nfs, /dev/hda3)    root_device\n" +
+      "  -a  Additional boot parameters\n" +
+      "\n" +
+      "Networking options:\n" +
+      "  -f  NFS root (if /dev/nfs specified)         nw_nfs_root\n" +
+      "  -s  NFS server                               nw_nfs_server\n" +
+      "  -4  Domain IPv4 address                      nw_ip\n" +
+      "  -g  Domain gateway                           nw_gw\n" +
+      "  -m  Domain net mask                          nw_mask\n" +
+      "  -h  Domain hostname                          nw_host\n" +
+      "\n" +
+      "Parameters to -d, -f, -4, -g, -h can be specified as patterns into\n" +
+      "which the allocated domain ID will be incorporated.  e.g.  for\n" +
+      "domain 1 patterns would expand as follows:\n" +
+      "\n" +
+      "  /dev/hda+       /dev/hda1\n" +
+      "  /dev/hda7+      /dev/hda8\n" +
+      "  128.232.8.50+   128.232.8.51\n" +
+      "\n" +
+      "Additionally, patterns for -4 -g -m can include an = which is\n" + 
+      "expanded to the corresponding setting from the calling domain.\n";
+  }
+}
diff --git a/tools/control/src/org/xenoserver/cmdline/ParseStart.java b/tools/control/src/org/xenoserver/cmdline/ParseStart.java
new file mode 100644 (file)
index 0000000..435e36a
--- /dev/null
@@ -0,0 +1,37 @@
+package org.xenoserver.cmdline;
+
+import org.xenoserver.control.Command;
+import org.xenoserver.control.CommandFailedException;
+import org.xenoserver.control.CommandStart;
+import org.xenoserver.control.Defaults;
+
+public class ParseStart extends CommandParser {
+
+  public void parse(Defaults d, String[] args) throws ParseFailedException, CommandFailedException {
+    int domain_id = getIntParameter(args, 'n', 0);
+    
+    if (domain_id == 0) {
+      throw new ParseFailedException("Expected -n<domain_id>");
+    }
+
+    String output = new CommandStart(d, domain_id).execute();
+    if ( output != null )
+      System.out.println( output );
+  }
+
+  public String getName()
+  {
+    return "start";
+  }
+
+  public String getUsage()
+  {
+    return "[-n<domain_id>]";
+  }
+
+  public String getHelpText()
+  {
+    return
+      "Start the specified domain.";
+  }
+}
diff --git a/tools/control/src/org/xenoserver/cmdline/ParseStop.java b/tools/control/src/org/xenoserver/cmdline/ParseStop.java
new file mode 100644 (file)
index 0000000..30aeadb
--- /dev/null
@@ -0,0 +1,37 @@
+package org.xenoserver.cmdline;
+
+import org.xenoserver.control.Command;
+import org.xenoserver.control.CommandFailedException;
+import org.xenoserver.control.CommandStop;
+import org.xenoserver.control.Defaults;
+
+public class ParseStop extends CommandParser {
+
+  public void parse(Defaults d, String[] args) throws ParseFailedException, CommandFailedException {
+    int domain_id = getIntParameter(args, 'n', 0);
+    
+    if (domain_id == 0) {
+      throw new ParseFailedException("Expected -n<domain_id>");
+    }
+
+    String output = new CommandStop(d, domain_id).execute();
+    if ( output != null )
+      System.out.println( output );
+  }
+
+  public String getName()
+  {
+    return "stop";
+  }
+
+  public String getUsage()
+  {
+    return "[-n<domain_id>]";
+  }
+
+  public String getHelpText()
+  {
+    return
+      "Stop the specified domain.";
+  }
+}
diff --git a/tools/control/src/org/xenoserver/control/Command.java b/tools/control/src/org/xenoserver/control/Command.java
new file mode 100644 (file)
index 0000000..a327f29
--- /dev/null
@@ -0,0 +1,27 @@
+package org.xenoserver.control;
+
+/**
+ * Subclasses of Command are responsible for applying changes to domain
+ * and virtual disk settings.
+ */
+public abstract class Command {
+  /**
+   * Subclasses should define an execute method which will apply the
+   * relevant change, if possible.
+   * 
+   * @return The results of executing the command, if successful, or null if
+   *         the command does not need to return results.
+   * @throws CommandFailedException if the command could not be completed.
+   */
+  public abstract String execute() throws CommandFailedException;
+
+  protected String reportCommand (String cmd_array[])
+  {
+    StringBuffer sb = new StringBuffer();
+    int i;
+    for (i = 0; i < cmd_array.length; i ++) {
+      sb.append (cmd_array[i] + " ");
+    }
+    return sb.toString();
+  }
+}
diff --git a/tools/control/src/org/xenoserver/control/CommandDestroy.java b/tools/control/src/org/xenoserver/control/CommandDestroy.java
new file mode 100644 (file)
index 0000000..bc1f65e
--- /dev/null
@@ -0,0 +1,58 @@
+package org.xenoserver.control;
+
+/**
+ * Destroys a domain.
+ */
+public class CommandDestroy extends Command {
+  private Defaults d;
+  private int domain_id;
+  private boolean force;
+
+  /**
+   * Constructor for CommandDestroy.
+   * 
+   * @param d Defaults object to use.
+   * @param domain_id Domain ID number to destroy.
+   * @param force Force destruction.
+   */
+  public CommandDestroy(Defaults d, int domain_id, boolean force) {
+    this.d = d;
+    this.domain_id = domain_id;
+    this.force = force;
+  }
+
+  public String execute() throws CommandFailedException {
+    Runtime r = Runtime.getRuntime();
+    String output = null;
+
+    try {
+      Process destroy_p;
+      String destroy_cmdarray[] = force ? new String[3] : new String[2];
+      int destroy_rc;
+      int idx = 0;
+      destroy_cmdarray[idx++] = d.XIToolsDir + "xi_destroy";
+      if (force) {
+        destroy_cmdarray[idx++] = "-f";
+      }
+      destroy_cmdarray[idx++] = "" + domain_id;
+
+      if (Settings.TEST) {
+        output = reportCommand(destroy_cmdarray);
+      } else {
+        destroy_p = r.exec(destroy_cmdarray);
+        destroy_rc = destroy_p.waitFor();
+
+        if (destroy_rc != 0) {
+          throw CommandFailedException.XICommandFailed("Could not destroy domain", destroy_cmdarray);
+        }
+        output = "Destroyed domain " + domain_id;
+      }
+    } catch (CommandFailedException e) {
+      throw e;
+    } catch (Exception e) {
+      throw new CommandFailedException("Could not destroy domain (" + e + ")", e);
+    }
+
+    return output;
+  }
+}
diff --git a/tools/control/src/org/xenoserver/control/CommandFailedException.java b/tools/control/src/org/xenoserver/control/CommandFailedException.java
new file mode 100644 (file)
index 0000000..f8571c3
--- /dev/null
@@ -0,0 +1,32 @@
+package org.xenoserver.control;
+
+/**
+ * Thrown to indicate that a command failed to execute.
+ */
+public class CommandFailedException extends Exception {
+  public CommandFailedException() {
+    super();
+  }
+
+  public CommandFailedException(String message) {
+    super(message);
+  }
+
+  public CommandFailedException(String message, Throwable cause) {
+    super(message, cause);
+  }
+
+  public CommandFailedException(Throwable cause) {
+    super(cause);
+  }
+  
+  public static CommandFailedException XICommandFailed(String message, String cmd_array[]) {
+    StringBuffer sb = new StringBuffer();
+    int i;
+    sb.append (message + " using: ");
+    for (i = 0; i < cmd_array.length; i ++) {
+      sb.append (cmd_array[i] + " ");
+    }
+    return new CommandFailedException( sb.toString() );    
+  }
+}
diff --git a/tools/control/src/org/xenoserver/control/CommandList.java b/tools/control/src/org/xenoserver/control/CommandList.java
new file mode 100644 (file)
index 0000000..af26225
--- /dev/null
@@ -0,0 +1,108 @@
+package org.xenoserver.control;
+
+import java.io.BufferedReader;
+import java.io.InputStreamReader;
+import java.util.StringTokenizer;
+import java.util.Vector;
+
+/**
+ * Lists details of all domains. After execute() has been called, call
+ * domains() to get the array of domains.
+ */
+public class CommandList extends Command {
+  private Defaults d;
+  private Domain[] array;
+
+  /**
+   * Constructor for CommandList.
+   * @param d Defaults object to use.
+   */
+  public CommandList(Defaults d) {
+    this.d = d;
+  }
+
+  /**
+   * Retrieves the list of domains.
+   * @return null, call domains() to get the list.
+   */
+  public String execute() throws CommandFailedException {
+    Runtime r = Runtime.getRuntime();
+    int rc = 0;
+    Vector v = new Vector();
+    String outline;
+    BufferedReader in;
+    String output = null;
+
+    try {
+      Process start_p;
+      String start_cmdarray[] = new String[1];
+      int start_rc;
+      start_cmdarray[0] = d.XIToolsDir + "xi_list";
+
+      if (Settings.TEST) {
+        output = reportCommand(start_cmdarray);
+      } else {
+        start_p = r.exec(start_cmdarray);
+        start_rc = start_p.waitFor();
+        if (start_rc != 0) {
+          throw CommandFailedException.XICommandFailed("Could not get domain list", start_cmdarray);
+        }
+
+        in =
+          new BufferedReader(new InputStreamReader(start_p.getInputStream()));
+
+        outline = in.readLine();
+        while (outline != null) {
+          Domain domain = new Domain();
+
+          StringTokenizer st = new StringTokenizer(outline);
+          if (st.hasMoreTokens()) {
+            domain.id = Integer.parseInt(st.nextToken());
+          }
+          if (st.hasMoreTokens()) {
+            domain.processor = Integer.parseInt(st.nextToken());
+          }
+          if (st.hasMoreTokens()) {
+            if (st.nextToken().equals("1")) {
+              domain.cpu = true;
+            } else {
+              domain.cpu = false;
+            }
+          }
+          if (st.hasMoreTokens()) {
+            domain.nstate = Integer.parseInt(st.nextToken());
+          }
+          if (st.hasMoreTokens()) {
+            domain.state = st.nextToken().toLowerCase();
+          }
+          if (st.hasMoreTokens()) {
+            domain.mcu = Integer.parseInt(st.nextToken());
+          }
+          if (st.hasMoreTokens()) {
+            domain.pages = Integer.parseInt(st.nextToken());
+          }
+          if (st.hasMoreTokens()) {
+            domain.name = st.nextToken();
+          }
+
+          v.add(domain);
+
+          outline = in.readLine();
+        }
+
+      }
+    } catch (CommandFailedException e) {
+      throw e;
+    } catch (Exception e) {
+      throw new CommandFailedException("Could not get domain list(" + e + ")", e);
+    }
+
+    array = new Domain[v.size()];
+    v.toArray(array);
+    return output;
+  }
+  
+  public Domain[] domains() {
+    return array;
+  }
+}
diff --git a/tools/control/src/org/xenoserver/control/CommandNew.java b/tools/control/src/org/xenoserver/control/CommandNew.java
new file mode 100644 (file)
index 0000000..4f32e97
--- /dev/null
@@ -0,0 +1,301 @@
+package org.xenoserver.control;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.zip.GZIPInputStream;
+
+/**
+ * Creates a new domain. As this command returns a multi-line result,
+ * call output() to get an array of strings.
+ */
+public class CommandNew extends Command {
+  private Defaults d;
+  private String name;
+  private int size;
+  private String image;
+  private String initrd;
+  private int vifs;
+  private String bargs;
+  private String root_dev;
+  private String nfs_root_path;
+  private String nw_ip;
+  private String nw_gw;
+  private String nw_mask;
+  private String nw_nfs_server;
+  private String nw_host;
+  private String[] output;
+  
+  public String[] output() {
+    return output;
+  }
+  
+  /**
+   * Constructor for CommandNew.
+   * @param d Defaults object to use.
+   * @param name Name for the domain.
+   * @param size Memory size for the domain.
+   * @param image Image to boot domain from.
+   * @param initrd Initrd to boot domain with.
+   * @param vifs Number of virtual interfaces for the domain.
+   * @param bargs Boot arguments for the domain.
+   * @param root_dev Root device for the domain.
+   * @param nfs_root_path NFS root to be used by the domain.
+   * @param nw_ip IP address pattern to use for the domain's interfaces.
+   * @param nw_gw Gateway to configure the domain for.
+   * @param nw_mask Network mask to configure the domain for.
+   * @param nw_nfs_server NFS server to be used by the domain.
+   * @param nw_host Hostname to be used by the domain.
+   */
+  public CommandNew(
+    Defaults d,
+    String name,
+    int size,
+    String image,
+    String initrd,
+    int vifs,
+    String bargs,
+    String root_dev,
+    String nfs_root_path,
+    String nw_ip,
+    String nw_gw,
+    String nw_mask,
+    String nw_nfs_server,
+    String nw_host) {
+    this.d = d;
+    this.name = name;
+    this.size = size;
+    this.image = image;
+    this.initrd = initrd;
+    this.vifs = vifs;
+    this.bargs = bargs;
+    this.root_dev = root_dev;
+    this.nfs_root_path = nfs_root_path;
+    this.nw_ip = nw_ip;
+    this.nw_gw = nw_gw;
+    this.nw_mask = nw_mask;
+    this.nw_nfs_server = nw_nfs_server;
+    this.nw_host = nw_host;
+  }
+
+  public String execute() throws CommandFailedException {
+    Runtime r = Runtime.getRuntime();
+    int domain_id = -1;
+    BufferedReader br;
+    int idx;
+    int i;
+    File image_tmp = null;
+    File initrd_tmp = null;
+    String domain_ip = "";
+    
+    String create_cmdarray[] = new String[3];
+    String build_cmdarray[] = new String[6];
+    String vifinit_cmdarray[] = new String[4];
+
+    try {
+      try {
+        /* Some initial sanity checks */
+        if (root_dev.equals("/dev/nfs") && (vifs == 0)) {
+          throw new CommandFailedException("Cannot use NFS root without VIFs configured");
+        }
+
+        /* Uncompress the image and initrd */
+        if (image.endsWith(".gz")) {
+          image_tmp = getUncompressed("xen-image-", image);
+          image = image_tmp.getPath();
+        }
+
+        if (initrd != null && initrd.endsWith(".gz")) {
+          initrd_tmp = getUncompressed("xen-initrd-", initrd);
+          initrd = initrd_tmp.getPath();
+        }
+
+        /* Create a new empty domain */
+        Process create_p;
+        int create_rc;
+        create_cmdarray[0] = d.XIToolsDir + "xi_create";
+        create_cmdarray[1] = "" + size;
+        create_cmdarray[2] = name;
+        if (Settings.TEST) {
+          reportCommand(create_cmdarray);
+          domain_id = 1;
+          create_rc = 0;
+        } else {
+          create_p = r.exec(create_cmdarray);
+          br =
+            new BufferedReader(
+              new InputStreamReader(create_p.getInputStream()));
+          domain_id = Integer.parseInt(br.readLine());
+          create_rc = create_p.waitFor();
+        }
+
+        if (create_rc != 0) {
+          throw CommandFailedException.XICommandFailed("Failed to create domain", create_cmdarray);
+        } else if (domain_id > d.MaxDomainNumber) {
+          throw new CommandFailedException(
+            "Cannot configure more than " + d.MaxDomainNumber + " domains");
+        }
+
+        /* Set up boot parameters to pass to xi_build. */
+        if (root_dev.equals("/dev/nfs")) {
+          if (vifs == 0) {
+            throw new CommandFailedException("Cannot use NFS root without VIFs configured");
+          }
+          if (nfs_root_path == null) {
+            throw new CommandFailedException("No NFS root specified");
+          }
+          if (nw_nfs_server == null) {
+            throw new CommandFailedException("No NFS server specified");
+          }
+          bargs =
+            (bargs
+              + " root=/dev/nfs "
+              + "nfsroot="
+              + StringPattern.parse(nfs_root_path).resolve(domain_id)
+              + " ");
+        } else {
+          bargs =
+            (bargs
+              + " root="
+              + StringPattern.parse(root_dev).resolve(domain_id)
+              + " ");
+
+        }
+
+        if (vifs > 0) {
+          domain_ip = InetAddressPattern.parse(nw_ip).resolve(domain_id);
+          if (nw_host == null) {
+            try {
+              nw_host = InetAddress.getByName(domain_ip).getHostName();
+            } catch (UnknownHostException uhe) {
+              nw_host = "" + nw_ip;
+            }
+
+          }
+          bargs =
+            ("ip="
+              + domain_ip
+              + ":"
+              + ((nw_nfs_server == null)
+                ? ""
+                : (InetAddressPattern.parse(nw_nfs_server).resolve(domain_id)))
+              + ":"
+              + ((nw_gw == null)
+                ? ""
+                : (InetAddressPattern.parse(nw_gw).resolve(domain_id)))
+              + ":"
+              + ((nw_mask == null)
+                ? ""
+                : InetAddressPattern.parse(nw_mask).resolve(domain_id))
+              + ":"
+              + ((nw_host == null) ? "" : nw_host)
+              + ":eth0:off "
+              + bargs);
+        }
+
+        /* Build the domain */
+        Process build_p;
+        int build_rc;
+        idx = 0;
+        for (i = 0; i < build_cmdarray.length; i++)
+          build_cmdarray[i] = "";
+        build_cmdarray[idx++] = d.XIToolsDir + "xi_build";
+        build_cmdarray[idx++] = "" + domain_id;
+        build_cmdarray[idx++] = "" + image;
+        build_cmdarray[idx++] = "" + vifs;
+        if (initrd != null)
+          build_cmdarray[idx++] = "initrd=" + initrd;
+        build_cmdarray[idx++] = "" + bargs;
+        if (Settings.TEST) {
+          reportCommand(build_cmdarray);
+          build_rc = 0;
+        } else {
+          build_p = r.exec(build_cmdarray);
+          build_rc = build_p.waitFor();
+        }
+
+        if (build_rc != 0) {
+          throw CommandFailedException.XICommandFailed("Failed to build domain", build_cmdarray);
+        }
+
+        /* Set up the first VIF if necessary */
+        if (vifs > 0) {
+          Process vifinit_p;
+          int vifinit_rc;
+          vifinit_cmdarray[0] = d.XIToolsDir + "xi_vifinit";
+          vifinit_cmdarray[1] = "" + domain_id;
+          vifinit_cmdarray[2] = "0";
+          vifinit_cmdarray[3] = domain_ip;
+          if (Settings.TEST) {
+            reportCommand(vifinit_cmdarray);
+            vifinit_rc = 0;
+          } else {
+            vifinit_p = r.exec(vifinit_cmdarray);
+            vifinit_rc = vifinit_p.waitFor();
+          }
+
+          if (vifinit_rc != 0) {
+            throw CommandFailedException.XICommandFailed(
+              "Failed to initialise VIF 0",
+              vifinit_cmdarray);
+          }
+        }
+      } finally {
+        if (image_tmp != null)
+          image_tmp.delete();
+        if (initrd_tmp != null)
+          initrd_tmp.delete();
+      }
+    } catch (CommandFailedException e) {
+      throw e;
+    } catch (Exception e) {
+      throw new CommandFailedException("Could not create new domain (" + e + ")", e);
+    }
+
+    output = new String[ vifs > 0 ? 6 : 4 ];
+    output[0] = "Domain created with arguments:";
+    output[1] = "";
+    for (i = 0; i < create_cmdarray.length; i++)
+      output[1] += create_cmdarray[i] + " ";
+    output[2] = "Domain built with arguments:";
+    output[3] = "";
+    for (i = 0; i < build_cmdarray.length; i++)
+      output[3] += build_cmdarray[i] + " ";
+    if ( vifs > 0 ) {
+      output[4] = "VIF 0 initialized with arguments:";
+      output[5] = "";
+      for (i = 0; i < vifinit_cmdarray.length; i++)
+        output[5] += vifinit_cmdarray[i] + " ";
+    }
+
+    return null;
+  }
+  
+  private File getUncompressed (String prefix, String original) throws IOException {
+    FileOutputStream fos;
+    GZIPInputStream gis;
+    File result;
+    byte buffer[] = new byte[1024];
+    int l;
+    
+    result = File.createTempFile (prefix, null);
+    
+    try {
+      fos = new FileOutputStream (result);
+      gis = new GZIPInputStream (new FileInputStream (original));
+      while ((l = gis.read(buffer, 0, buffer.length)) != -1) {
+  fos.write (buffer, 0, l);
+      }   
+    } catch (IOException ioe) {
+      result.delete ();
+      throw ioe;
+    }
+
+    return result;
+  }
+}
diff --git a/tools/control/src/org/xenoserver/control/CommandStart.java b/tools/control/src/org/xenoserver/control/CommandStart.java
new file mode 100644 (file)
index 0000000..7722ccd
--- /dev/null
@@ -0,0 +1,49 @@
+package org.xenoserver.control;
+
+/**
+ * Starts a domain.
+ */
+public class CommandStart extends Command {
+  private Defaults d;
+  private int domain_id;
+  
+  /**
+   * Constructor for CommandStart.
+   * @param d Defaults object to use.
+   * @param domain_id Domain to start.
+   */
+  public CommandStart(Defaults d, int domain_id) {
+    this.d = d;
+    this.domain_id = domain_id;
+  }
+
+  public String execute() throws CommandFailedException {
+    Runtime r = Runtime.getRuntime();
+    String output = null;
+
+    try {
+      Process start_p;
+      String start_cmdarray[] = new String[2];
+      int start_rc;
+      start_cmdarray[0] = d.XIToolsDir + "xi_start";
+      start_cmdarray[1] = "" + domain_id;
+
+      if (Settings.TEST) {
+        output = reportCommand(start_cmdarray);
+      } else {
+        start_p = r.exec(start_cmdarray);
+        start_rc = start_p.waitFor();
+        if (start_rc != 0) {
+          throw CommandFailedException.XICommandFailed("Could not start domain", start_cmdarray);
+        }
+        output = "Started domain " + domain_id;
+      }
+    } catch (CommandFailedException e) {
+      throw e;
+    } catch (Exception e) {
+      throw new CommandFailedException("Could not start new domain (" + e + ")", e);
+    }
+
+    return output;
+  }
+}
diff --git a/tools/control/src/org/xenoserver/control/CommandStop.java b/tools/control/src/org/xenoserver/control/CommandStop.java
new file mode 100644 (file)
index 0000000..d280875
--- /dev/null
@@ -0,0 +1,50 @@
+package org.xenoserver.control;
+
+/**
+ * Stops a domain.
+ */
+public class CommandStop extends Command {
+  private Defaults d;
+  private int domain_id;
+  
+  /**
+   * Constructor for CommandStop.
+   * @param d The defaults object to use.
+   * @param domain_id The domain to stop.
+   */
+  public CommandStop(Defaults d, int domain_id) {
+    this.d = d;
+    this.domain_id = domain_id;
+  }
+
+  public String execute() throws CommandFailedException {
+    Runtime r = Runtime.getRuntime();
+    String output = null;
+
+    try {
+      Process stop_p;
+      String stop_cmdarray[] = new String[2];
+      int stop_rc;
+      stop_cmdarray[0] = d.XIToolsDir + "xi_stop";
+      stop_cmdarray[1] = "" + domain_id;
+
+      if (Settings.TEST) {
+        output = reportCommand(stop_cmdarray);
+      } else {
+        stop_p = r.exec(stop_cmdarray);
+        stop_rc = stop_p.waitFor();
+
+        if (stop_rc != 0) {
+          throw CommandFailedException.XICommandFailed("Could not stop domain", stop_cmdarray);
+        }
+        output = "Stopped domain " + domain_id;
+      }
+    } catch (CommandFailedException e) {
+      throw e;
+    } catch (Exception e) {
+      throw new CommandFailedException("Could not stop new domain (" + e + ")", e);
+    }
+
+    return output;
+  }
+}
diff --git a/tools/control/src/org/xenoserver/control/Defaults.java b/tools/control/src/org/xenoserver/control/Defaults.java
new file mode 100644 (file)
index 0000000..61fd47f
--- /dev/null
@@ -0,0 +1,205 @@
+package org.xenoserver.control;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+
+import org.xml.sax.Attributes;
+import org.xml.sax.InputSource;
+import org.xml.sax.XMLReader;
+import org.xml.sax.helpers.DefaultHandler;
+
+/**
+ * The Defaults class stores the default settings to be used by the
+ * management utilities. On construction it parses the defaults file
+ * located through the Settings class.
+ */
+public class Defaults
+{
+  public String domainName;
+
+  public int domainSizeKB;
+  public String domainImage;
+  public String domainInitRD;
+  public int domainVIFs;
+
+  public String rootDevice;
+
+  public String NWIP;
+  public String NWGW;
+  public String NWMask;
+  public String NWHost;
+
+  public String NWNFSServer;
+  public String NWNFSRoot;
+
+  public int MaxDomainNumber = Integer.MAX_VALUE;
+  public String args = "";
+
+  public String XIToolsDir = "";
+
+  /***********************************************************************/
+
+  public Defaults ()
+  {
+    File f = Settings.getDefaultsFile ();
+
+    if (f == null)
+    {
+      return;
+    }
+
+    try
+      {
+       XMLReader xr = new org.apache.crimson.parser.XMLReaderImpl();
+       Handler handler = new Handler ();
+       xr.setContentHandler (handler);
+       xr.setErrorHandler (handler);
+       xr.parse (new InputSource(new FileReader (f)));
+      }
+    catch (Exception e) 
+      {
+       System.err.println ("Could not read defaults file " + f +
+                           "\nException: " + e);
+       e.printStackTrace();
+       return;
+      }
+  }
+
+  public void describe () {
+    System.out.println ("Domain defaults:");
+    System.out.println ("   name            " + domainName);
+    System.out.println ("   size            " + domainSizeKB);
+    System.out.println ("   vifs            " + domainVIFs);
+    System.out.println ("   domainImage     " + domainImage);
+    System.out.println ("   domainInitRD    " + domainInitRD);
+    System.out.println ("   rootDevice      " + rootDevice);
+    System.out.println ("   NWIP            " + NWIP);
+    System.out.println ("   NWGW            " + NWGW);
+    System.out.println ("   NWMask          " + NWMask);
+    System.out.println ("   MaxDomainNumber " + MaxDomainNumber);
+    System.out.println ("   NWNFSServer     " + NWNFSServer);
+    System.out.println ("   NWNFSRoot       " + NWNFSRoot);
+    System.out.println ("   XIToolsDir      " + XIToolsDir);
+    System.out.println ("   args            " + args);
+  }
+
+  /***********************************************************************/
+
+  class Handler extends DefaultHandler
+  {
+    boolean inDomctlDefaults;
+    String lastName;
+
+    public void startDocument ()
+    {
+    }
+
+    public void endDocument ()
+    {
+    }
+
+    public void startElement (String uri, String name,
+                             String qname, Attributes atts)
+    {
+      if (qname.equals ("domctl_defaults")) {
+       inDomctlDefaults = true;
+      } else {
+       lastName = qname;
+      }
+    }
+
+    public void endElement (String uri, String name, String qname)
+    {
+      lastName = "";
+      if (qname.equals ("domctl_defaults")) {
+       inDomctlDefaults = false;
+      }
+    }
+    
+    public void characters (char ch[], int start, int length)
+    {
+      String s = new String (ch, start, length);
+      if (lastName != null)
+       {
+         if (lastName.equals ("domain_size_kb")) {
+           domainSizeKB = Integer.parseInt (s);
+         } else if (lastName.equals ("domain_image")) {
+           domainImage = s;
+         } else if (lastName.equals ("domain_name")) {
+           domainName = s;
+         } else if (lastName.equals ("domain_init_rd")) {
+           domainInitRD = s;
+         } else if (lastName.equals ("domain_vifs")) {
+           domainVIFs = Integer.parseInt (s);
+         } else if (lastName.equals ("root_device")) {
+           rootDevice = s;
+         } else if (lastName.equals ("nw_ip")) {
+           NWIP = expandDefault (s, runCommand(XIToolsDir+Settings.XI_HELPER+" ip").trim());
+         } else if (lastName.equals ("nw_gw")) {
+           NWGW = expandDefault (s, runCommand(XIToolsDir+Settings.XI_HELPER+" route").trim());
+         } else if (lastName.equals ("nw_mask")) {
+           NWMask = expandDefault (s, runCommand(XIToolsDir+Settings.XI_HELPER+" mask").trim());
+         } else if (lastName.equals ("nw_host")) {
+           NWHost = s;
+         } else if (lastName.equals ("nw_nfs_server")) {
+           NWNFSServer = s;
+         } else if (lastName.equals ("nw_nfs_root")) {
+           NWNFSRoot = s;
+         } else if (lastName.equals ("args")) {
+           args = s;
+         } else if (lastName.equals ("max_domain_number")) {
+           MaxDomainNumber = Integer.parseInt(s);
+         } else if (lastName.equals ("xi_tools_dir")) {
+           XIToolsDir = s;
+         }
+       }
+    }
+  }
+
+  public String expandDefault (String supplied, String self)
+  {
+    if (supplied.startsWith ("=")) {
+      if (supplied.length() > 1) {
+       return self + supplied.substring (1, supplied.length());
+      } else {
+       return self;
+      }
+    } else {
+      return supplied;
+    }
+  }
+
+  
+  public String
+    runCommand (String command)
+  {
+    Runtime runtime = Runtime.getRuntime();
+    String outline;
+    StringBuffer output = new StringBuffer();
+
+    try
+    {
+      Process process = runtime.exec(command);
+      BufferedReader in = new BufferedReader(
+                         new InputStreamReader(process.getInputStream()));
+
+      outline = in.readLine();
+      while (outline != null)
+      {
+        output.append("\n" + outline);
+        outline = in.readLine();
+      }
+    }
+    catch (IOException e)
+    {
+      return e.toString();
+    }
+
+    return output.toString();
+  }
+
+
+}
diff --git a/tools/control/src/org/xenoserver/control/Domain.java b/tools/control/src/org/xenoserver/control/Domain.java
new file mode 100644 (file)
index 0000000..27f9ec9
--- /dev/null
@@ -0,0 +1,31 @@
+package org.xenoserver.control;
+
+/**
+ * A Domain object holds the details of one domain suitable for returning
+ * from methods enquiring about domain status.
+ */
+public class
+Domain
+{
+  public int id;                                                /* domain id */
+  public int processor;                                         /* processor */
+  public boolean cpu;                                             /* has cpu */
+  public int   nstate;                                              /* state */
+  public String state;            /* running, interruptable, uninterruptable,
+                                                     wait, suspended, dying */
+  public int mcu;                                            /* mcu advances */
+  public int pages;                                           /* total pages */
+  public String name;                                                /* name */
+
+  Domain()
+  {
+    id = 0;
+    processor = 0;
+    cpu = false;
+    nstate = 0;
+    state = "";
+    mcu = 0;
+    pages = 0;
+    name = "none";
+  }
+}
diff --git a/tools/control/src/org/xenoserver/control/InetAddressPattern.java b/tools/control/src/org/xenoserver/control/InetAddressPattern.java
new file mode 100644 (file)
index 0000000..7b45b09
--- /dev/null
@@ -0,0 +1,60 @@
+package org.xenoserver.control;
+
+import java.net.*;
+
+public class InetAddressPattern
+{
+  InetAddress base;
+  boolean addDom;
+
+  static InetAddressPattern parse (String t)
+  {
+    InetAddressPattern result = new InetAddressPattern ();
+    char[] ca = t.toCharArray ();
+    int idx = 0;
+    int len = ca.length;
+
+    try {
+      if (len == 0) {
+       result.base = null;
+       result.addDom = false;
+      } else if (ca[len - 1] == '+') {
+       result.base = InetAddress.getByName(t.substring(0, len - 1));
+       result.addDom = true;
+      } else {
+       result.base = InetAddress.getByName(t);
+       result.addDom = false;
+      }
+    } catch (UnknownHostException uhe) {
+      result.base = null;
+      result.addDom = false;
+    }
+
+    return result;
+  }
+
+  public String resolve (int domain_id) {
+    byte b[] = base.getAddress ();
+    if (addDom) {
+      if (((int)b[3]) + domain_id > 255) {
+       if (((int)b[2]) + domain_id > 255) {
+         if (((int)b[1]) + domain_id > 255) {
+           b[0] ++;
+         }
+         b[1] ++;
+       }
+       b[2] ++;
+      }
+      b[3] += domain_id;
+    }
+    return "" + 
+      (b[0] + (b[0] < 0 ? 256 : 0)) + "." + 
+      (b[1] + (b[1] < 0 ? 256 : 0)) + "." + 
+      (b[2] + (b[2] < 0 ? 256 : 0)) + "." + 
+      (b[3] + (b[3] < 0 ? 256 : 0));
+  }
+
+  public String toString () {
+    return "[" + base + (addDom ? "+dom_id" : "") + "]";
+  }
+}
diff --git a/tools/control/src/org/xenoserver/control/Settings.java b/tools/control/src/org/xenoserver/control/Settings.java
new file mode 100644 (file)
index 0000000..74203e6
--- /dev/null
@@ -0,0 +1,41 @@
+package org.xenoserver.control;
+
+import java.io.File;
+import java.util.StringTokenizer;
+
+/**
+ * The Settings class is a repository for global settings such as the IP of
+ * the machine and the location of the defaults file.
+ */
+public final class Settings
+{
+  public static final String DEFAULTS_FILE = System.getProperty ("DEFAULTS_FILE", "domctl.xml");
+  public static final String DEFAULTS_PATH = System.getProperty ("DEFAULTS_PATH", ".:/etc:/var/lib/xen");
+  public static final String LOCAL_IP = System.getProperty ("LOCAL_IP");
+  public static final String LOCAL_MASK = System.getProperty ("LOCAL_MASK");
+  public static final String LOCAL_GW = System.getProperty ("LOCAL_ROUTE");
+  public static final boolean TEST = (System.getProperty ("TEST") != null);
+  public static final String XI_HELPER = System.getProperty ("XI_HELPER", "xi_helper");
+
+
+  public static File getDefaultsFile() {
+    StringTokenizer tok = new StringTokenizer (DEFAULTS_PATH, ":");
+    File result = null;
+    File probe;
+
+    while (tok.hasMoreTokens ()) {
+      String probe_dir = tok.nextToken ();
+      probe = new File (probe_dir, DEFAULTS_FILE);
+      if (probe.exists ()) {
+       result = probe;
+       break;
+      }
+    }
+
+    if (result == null) {
+      System.err.println ("Could not find " + DEFAULTS_FILE + " in path " + DEFAULTS_PATH);
+    }
+
+    return result;
+  }
+}
diff --git a/tools/control/src/org/xenoserver/control/StringPattern.java b/tools/control/src/org/xenoserver/control/StringPattern.java
new file mode 100644 (file)
index 0000000..5df2470
--- /dev/null
@@ -0,0 +1,59 @@
+package org.xenoserver.control;
+
+public class StringPattern
+{
+  String base;
+  int bn;
+  boolean addDom;
+  boolean appendDom;
+
+  static StringPattern parse (String t)
+  {
+    StringPattern result = new StringPattern ();
+    char[] ca = t.toCharArray ();
+    int idx = 0;
+    int len = ca.length;
+
+    if (len == 0) {
+      result.base = "";
+      result.bn = 0;
+      result.addDom = false;
+    } else if (ca[len - 1] == '+') {
+      idx = len - 2;
+      if ((idx >= 0) && (ca[idx] >= '0') && (ca[idx] <= '9')) {
+       while ((idx >= 0) && (ca[idx] >= '0') && (ca[idx] <= '9')) {
+         idx --;
+       }
+       result.base = t.substring(0, idx + 1);
+       result.bn = Integer.parseInt (t.substring (idx + 1, len - 1));
+       result.addDom = true;
+      } else {
+       result.base = t.substring(0, len - 1);
+       result.appendDom = true;
+      }
+    } else {
+      result.base = t;
+    }
+
+    return result;
+  }
+
+  public String resolve (int domain_id) {
+    if (addDom) {
+      return base + (bn + domain_id);
+    } else if (appendDom) {
+      return base + domain_id;
+    } else {
+      return base;
+    }
+  }
+
+  public String toString () {
+    return ("[" + 
+           base + 
+           (addDom ? "+" + bn : "") + 
+           ((addDom || appendDom) ? "+ID" : "") + 
+           "]");
+  }
+
+}
diff --git a/tools/control/xenctl b/tools/control/xenctl
new file mode 100755 (executable)
index 0000000..17ec375
--- /dev/null
@@ -0,0 +1,33 @@
+#!/bin/bash 
+
+if [ -z "$DEFAULTS_FILE" ] ; then DEFAULTS_FILE=domctl.xml ; fi
+if [ -z "$DEFAULTS_PATH" ] ; then DEFAULTS_PATH=.:/etc:/var/lib/xen ; fi
+if [ -z "$QUERY_DEV" ] ; then QUERY_DEV=eth0 ; fi
+if [ -z "$IFCONFIG" ] ; then IFCONFIG=/sbin/ifconfig ; fi
+if [ -z "$ROUTE" ] ; then ROUTE=/sbin/route ; fi
+if [ -z "$JAVA" ] ; then JAVA=java ; fi
+
+if [ "$1" = "new" ] ; then
+  if [ ! -x "$IFCONFIG" ]; then  
+    echo Could not find executable $IFCONFIG
+    exit 1
+  fi
+
+  if [ ! -x "$ROUTE" ]; then
+    echo Could not find executable $ROUTE
+    exit 1
+  fi
+
+  # Try to determine dom0 network settings to avoid hard-coding
+  # particular machines in the defaults file
+  LOCAL_IP=$(/sbin/ifconfig $QUERY_DEV | grep 'inet addr' | tr ':' '\t' | awk '{print $3}')
+  LOCAL_MASK=$(/sbin/ifconfig $QUERY_DEV | grep 'Mask' | tr ':' '\t' | awk '{print $7}')
+  LOCAL_ROUTE=$(/sbin/route -n | grep $QUERY_DEV | grep 'G' | awk '{print $2}')
+fi
+
+
+#ARGS="-DTEST -DDEFAULTS_FILE=$DEFAULTS_FILE -DDEFAULTS_PATH=$DEFAULTS_PATH -DLOCAL_IP=$LOCAL_IP -DLOCAL_MASK=$LOCAL_MASK -DLOCAL_ROUTE=$LOCAL_ROUTE"
+ARGS="-DDEFAULTS_FILE=$DEFAULTS_FILE -DDEFAULTS_PATH=$DEFAULTS_PATH -DLOCAL_IP=$LOCAL_IP -DLOCAL_MASK=$LOCAL_MASK -DLOCAL_ROUTE=$LOCAL_ROUTE"
+
+
+$JAVA $ARGS -jar $(dirname $0)/xenctl-cmdline.jar $*